﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Xml;

//DT
using System.Web.Services.Protocols; // for SoapException

namespace parking
{
    public class ReservationImpl
    {
        static dbDataContext db = new dbDataContext();
    
        // DT 
        // RETURN A RESERVATION ID IF SUCCESSFULL, ELSE -1
        internal static int reserveSpot(string email, string starttime, string endtime, int spotId)
        {
            // NOTE: In this time format starttime and endtime is MM/DD/YY HH:MM (MUST be in military hours)
            
            // Get the user object first
            user myUser = (from u in db.users 
                           where u.email == email
                           select u).FirstOrDefault();

            decimal total = 0.0m;
            bool isVisitor = false;

            // Check IF Student 
            if (myUser != null && myUser.accountType == AccountImpl.ACCOUNT_STUDENT)
            {
                total = 0.0m; // STUDENT No need to calculate
            }
            // Check IF STAFF - $0 //
            else 
                if (myUser != null && myUser.accountType == AccountImpl.ACCOUNT_STAFF)
                {
                    total = 0.0m; // STAFF is free
                }
                // Check IF ADMIN - $0 //
                else
                    if (myUser != null && myUser.accountType == AccountImpl.ACCOUNT_ADMIN)
                    {
                        total = 0.0m; // ADMIN is free
                    }
                    else  // IF VISITOR
                    {
                        isVisitor = true;
                        total = ComputeParkingCost(starttime, endtime);
                    }

            // MAKE A RESERVATION HERE based on the parameter spotId and UPDATE the database
            // No need to check the availability first or not because by this point, the spotId must be available.
            // Create the reservation object
            reservation myRes = new reservation();
            if (isVisitor)
                myRes.userId = 9999;
            else
                myRes.userId = myUser.id;
            myRes.starttime = Convert.ToDateTime(starttime);
            myRes.endtime = Convert.ToDateTime(endtime);
            myRes.spotId = spotId;
            myRes.totaldue = total;

            // Add/Insert to the reservation DB
            db.reservations.InsertOnSubmit(myRes);
            db.SubmitChanges();

            return myRes.reservationId;
        }


        internal static string getReservationDetails(int reservationId)
        {
            //get the reservation from DB
            reservation myRes = (from r in db.reservations
                           where r.reservationId == reservationId
                           select r).SingleOrDefault();

            //get the user from DB
            //get the user from DB
            user myUser = (from u in db.users
                           where u.id == myRes.userId
                           select u).SingleOrDefault();

            //create the root node of the xml
            XmlDocument doc = new XmlDocument();
            XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
            doc.AppendChild(docNode);

            XmlNode resNode = doc.CreateElement("reservation");
            doc.AppendChild(resNode);

            //add id
            XmlAttribute attr = doc.CreateAttribute("id");
            attr.Value = myRes.reservationId.ToString();
            resNode.Attributes.Append(attr);

            //add the rest of account details as members
            XmlNode propNode = doc.CreateElement("accountid");
            propNode.AppendChild(doc.CreateTextNode(myRes.userId.ToString()));
            resNode.AppendChild(propNode);



            propNode = doc.CreateElement("email");
            propNode.AppendChild(doc.CreateTextNode(myUser.email));
            resNode.AppendChild(propNode);

            propNode = doc.CreateElement("starttime");
            propNode.AppendChild(doc.CreateTextNode(myRes.starttime.ToString()));
            resNode.AppendChild(propNode);

            propNode = doc.CreateElement("endtime");
            propNode.AppendChild(doc.CreateTextNode(myRes.endtime.ToString()));
            resNode.AppendChild(propNode);

            propNode = doc.CreateElement("spotId");
            propNode.AppendChild(doc.CreateTextNode(myRes.spotId.ToString()));
            resNode.AppendChild(propNode);

            propNode = doc.CreateElement("totaldue");
            propNode.AppendChild(doc.CreateTextNode(myRes.totaldue.ToString()));
            resNode.AppendChild(propNode);

            //convert the XML into string
            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);

            doc.WriteTo(xmlTextWriter);
            xmlTextWriter.Flush();

            return stringWriter.GetStringBuilder().ToString();
        }

        internal static bool cancelReservation(int resvId)
        {
            // Get the reservation from the db
            var cancelRsvp = (from result in db.reservations
                             where result.reservationId == resvId
                             select result).ToList();

            if (cancelRsvp.Count != 0)
            {
                //Delete the reservation from the database
                db.reservations.DeleteAllOnSubmit(cancelRsvp);
                try 
                {
                    db.SubmitChanges();
                }
                catch (Exception ex)
                {
                    throw new SoapException("Reservation cannot be deleted", SoapException.ClientFaultCode);
                }
                return true;
            }
            else
                return false;
        }

        //DT
        internal static string getAllReservationList()
        {
            //get the reservation from DB
            var myRes =  (from r in db.reservations
                          select r).ToList();

            //create the root node of the xml
            XmlDocument doc = new XmlDocument();
            XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
            doc.AppendChild(docNode);

            XmlNode resParentNode = doc.CreateElement("reservations");
            doc.AppendChild(resParentNode);

            foreach(reservation rsv in myRes)
            {
                XmlNode resNode = doc.CreateElement("reservation");
                
                //add id
                XmlAttribute attr = doc.CreateAttribute("id");
                attr.Value = rsv.reservationId.ToString();
                resNode.Attributes.Append(attr);

                //add the rest of account details as members
                XmlNode propNode = doc.CreateElement("userid");
                propNode.AppendChild(doc.CreateTextNode(rsv.userId.ToString()));
                resNode.AppendChild(propNode);

                //get email address
                
                user myUser = (from u in db.users
                               where u.id == rsv.userId
                               select u).FirstOrDefault();

                propNode = doc.CreateElement("email");
                propNode.AppendChild(doc.CreateTextNode(myUser.email));
                resNode.AppendChild(propNode);


                propNode = doc.CreateElement("starttime");
                propNode.AppendChild(doc.CreateTextNode(rsv.starttime.ToString()));
                resNode.AppendChild(propNode);

                propNode = doc.CreateElement("endtime");
                propNode.AppendChild(doc.CreateTextNode(rsv.endtime.ToString()));
                resNode.AppendChild(propNode);

                propNode = doc.CreateElement("spotId");
                propNode.AppendChild(doc.CreateTextNode(rsv.spotId.ToString()));
                resNode.AppendChild(propNode);

                propNode = doc.CreateElement("totaldue");
                propNode.AppendChild(doc.CreateTextNode(rsv.totaldue.ToString()));
                resNode.AppendChild(propNode);

                resParentNode.AppendChild(resNode);
            }

            //convert the XML into string
            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);

            doc.WriteTo(xmlTextWriter);
            xmlTextWriter.Flush();

            return stringWriter.GetStringBuilder().ToString();
        }

        internal static string getReservationByEmail(string email)
        {
            //get the account id from the email first
            user myUser = (from u in db.users
                           where u.email == email
                           select u).FirstOrDefault();

            //get the reservation from DB
            var myRes = (from r in db.reservations
                         where r.userId == myUser.id
                         select r).ToList();

            //create the root node of the xml
            XmlDocument doc = new XmlDocument();
            XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
            doc.AppendChild(docNode);

            XmlNode resParentNode = doc.CreateElement("reservations");
            doc.AppendChild(resParentNode);

            foreach (reservation rsv in myRes)
            {
                XmlNode resNode = doc.CreateElement("reservation");

                //add id
                XmlAttribute attr = doc.CreateAttribute("id");
                attr.Value = rsv.reservationId.ToString();
                resNode.Attributes.Append(attr);

                //add the rest of account details as members
                XmlNode propNode = doc.CreateElement("userid");
                propNode.AppendChild(doc.CreateTextNode(rsv.userId.ToString()));
                resNode.AppendChild(propNode);

                //get email address

                myUser = (from u in db.users
                               where u.id == rsv.userId
                               select u).FirstOrDefault();

                propNode = doc.CreateElement("email");
                propNode.AppendChild(doc.CreateTextNode(myUser.email));
                resNode.AppendChild(propNode);


                propNode = doc.CreateElement("starttime");
                propNode.AppendChild(doc.CreateTextNode(rsv.starttime.ToString()));
                resNode.AppendChild(propNode);

                propNode = doc.CreateElement("endtime");
                propNode.AppendChild(doc.CreateTextNode(rsv.endtime.ToString()));
                resNode.AppendChild(propNode);

                propNode = doc.CreateElement("spotId");
                propNode.AppendChild(doc.CreateTextNode(rsv.spotId.ToString()));
                resNode.AppendChild(propNode);

                propNode = doc.CreateElement("totaldue");
                propNode.AppendChild(doc.CreateTextNode(rsv.totaldue.ToString()));
                resNode.AppendChild(propNode);

                resParentNode.AppendChild(resNode);
            }

            //convert the XML into string
            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);

            doc.WriteTo(xmlTextWriter);
            xmlTextWriter.Flush();

            return stringWriter.GetStringBuilder().ToString();
        }

        private static decimal ComputeParkingCost(string starttime, string endtime)
        {
            // INIT THE COST OF PARKING
            decimal total = 0.00m;  //m:represents a decimal number
            /*
            // PARSE THE TIME FORMAT
            var parts = starttime.Split(':');
            string startHour = parts[0];
            string startMin = parts[1];

            parts = endtime.Split(':');
            string endHour = parts[0];
            string endMin = parts[1];

            DateTime startTime = new DateTime(2012, 12, 12, Convert.ToInt32(startHour), Convert.ToInt32(startMin), 0);  //Convert.ToDateTime(starttime);
            //startTime.AddHours(Convert.ToDouble(starttime));

            DateTime endTime = new DateTime(2012, 12, 12, Convert.ToInt32(endHour), Convert.ToInt32(endMin), 0);  //Convert.ToDateTime(endtime);
            //endTime.AddHours(Convert.ToDouble(endtime));

            // Make sure endTime > startTime, if IT IS, then calculate the rate per hour is $1.50.
            if (endTime.CompareTo(startTime) > 0)
            {
                TimeSpan elapsedTime = endTime.Subtract(startTime);     //endTime.Millisecond - startTime.Millisecond;  // = endTime.Hour - startTime.Hour;
                total = Convert.ToDecimal(elapsedTime.Hours * 1.50);
            }
             */

            DateTime start = Convert.ToDateTime(starttime);
            DateTime end = Convert.ToDateTime(endtime);

            
            TimeSpan span = end.Subtract(start);
            int hours = (int) Math.Ceiling(span.TotalHours);

            if (hours > 0)
            {
                total = hours * 1.50m;
            }
            return total;
        }

    }//end class
}//end namespace